use crate::global::{CURRENT_THREAD, MAX_PRIORITY, SCHEDULE_FLAG, SCHEDULE_LIST};
use rtt_kernel_cpu::context::rt_context_switch;
use rtt_kernel_cpu::context::rt_context_switch_to;
use rtt_kernel_io::dbg;
use rtt_kernel_io::print;
use rtt_kernel_mutex::SCHEDULER_LOCK_NESTED;

// 调度器
pub fn rt_schedule() {
    {
        let flag = SCHEDULE_FLAG.lock();
        if !(*flag) {
            dbg!("Not schedule，Flag is disable!\n");
            return;
        }
    }
    let mut cur_th = CURRENT_THREAD.lock();
    {
        // 正在使用线程锁，不进行调度
        if !SCHEDULER_LOCK_NESTED.scheduler_able() {
            // 当前的线程被额外阻塞，产生了死锁
            if cur_th.is_sp() {
                dbg!("Dead Lock!\n");
            } else {
                return;
            }
        }
    }

    let mut schedule_list = SCHEDULE_LIST.lock();


    let mut to_th = None;
    let search_range;

    // 保证不会切换到更低的优先级
    if cur_th.is_thread() {
        search_range = cur_th.thread_get_thread().get_priority() + 1;
    } else {
        search_range = MAX_PRIORITY;
    }

    // 搜索准备切换到的线程
    for i in 0..search_range {
        let th = schedule_list[i].pop_front();
        match th {
            Some(i) => {
                to_th = Some(i);
            }
            None => {}
        }
    }

    dbg!(match to_th {
        None => {
            print!("not find thread to switch\n");
        }
        Some(ref a) => {
            print!("find thread[{}] to switch\n", a.get_name());
        }
    });

    match to_th {
        None => {
            return;
        }
        Some(a) => {
            if cur_th.is_null() {
                dbg!("switch thread from null, null: dead thread or init");
                let to_sp;
                {
                    let to = a.get_sp().lock();
                    to_sp = &*to as *const _ as u32;
                }
                cur_th.null_set_thread(a);
                rt_context_switch_to(to_sp);
            } else if cur_th.is_sp() {
                dbg!("switch thread from sp");
                let to_sp;
                let from_sp;
                {
                    let to = a.get_sp().lock();
                    to_sp = &*to as *const _ as u32;
                }
                let cur = cur_th.sp_set_thread(a);
                {
                    from_sp = &*cur as *const _ as u32;
                }
                if to_sp == from_sp {
                    dbg!("Sp is same as to thread sp, not schedule.");
                    return;
                }
                rt_context_switch(from_sp, to_sp);
            } else {
                let to_sp;
                let from_sp;
                {
                    let to = a.get_sp().lock();
                    to_sp = &*to as *const _ as u32;
                }
                let cur = cur_th.thread_update_thread(a);
                dbg!("switch thread from another thread[{}]", cur.get_name());
                {
                    let cur = cur.get_sp().lock();
                    from_sp = &*cur as *const _ as u32;
                }
                schedule_list[cur.get_priority()].push_back(cur);
                rt_context_switch(from_sp, to_sp);
            }
        }
    }
}

pub fn rt_schedule_enable() {
    let mut flag = SCHEDULE_FLAG.lock();
    *flag = true;
}

pub fn rt_schedule_disable() {
    let mut flag = SCHEDULE_FLAG.lock();
    *flag = false;
}
